/*
Copyright 2006 Jerry Huxtable

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package com.jhlabs.image;

import java.awt.image.*;
import com.jhlabs.math.*;

// TODO: Auto-generated Javadoc
/**
 * The Class TextureFilter.
 */
public class TextureFilter extends PointFilter {

	/** The scale. */
	private float scale = 32;
	
	/** The stretch. */
	private float stretch = 1.0f;
	
	/** The angle. */
	private float angle = 0.0f;
	
	/** The amount. */
	public float amount = 1.0f;
	
	/** The turbulence. */
	public float turbulence = 1.0f;
	
	/** The gain. */
	public float gain = 0.5f;
	
	/** The bias. */
	public float bias = 0.5f;
	
	/** The operation. */
	public int operation;
	
	/** The m00. */
	private float m00 = 1.0f;
	
	/** The m01. */
	private float m01 = 0.0f;
	
	/** The m10. */
	private float m10 = 0.0f;
	
	/** The m11. */
	private float m11 = 1.0f;
	
	/** The colormap. */
	private Colormap colormap = new Gradient();
	
	/** The function. */
	private Function2D function = new Noise();

	/**
	 * Instantiates a new texture filter.
	 */
	public TextureFilter() {
	}

	/**
	 * Set the amount of texture.
	 * @param amount the amount
     * @min-value 0
     * @max-value 1
     * @see #getAmount
	 */
	public void setAmount(float amount) {
		this.amount = amount;
	}

	/**
	 * Get the amount of texture.
	 * @return the amount
     * @see #setAmount
	 */
	public float getAmount() {
		return amount;
	}

	/**
	 * Sets the function.
	 * 
	 * @param function
	 *            the new function
	 */
	public void setFunction(Function2D function) {
		this.function = function;
	}

	/**
	 * Gets the function.
	 * 
	 * @return the function
	 */
	public Function2D getFunction() {
		return function;
	}

	/**
	 * Sets the operation.
	 * 
	 * @param operation
	 *            the new operation
	 */
	public void setOperation(int operation) {
		this.operation = operation;
	}
	
	/**
	 * Gets the operation.
	 * 
	 * @return the operation
	 */
	public int getOperation() {
		return operation;
	}
	
	/**
     * Specifies the scale of the texture.
     * @param scale the scale of the texture.
     * @min-value 1
     * @max-value 300+
     * @see #getScale
     */
	public void setScale(float scale) {
		this.scale = scale;
	}

	/**
     * Returns the scale of the texture.
     * @return the scale of the texture.
     * @see #setScale
     */
	public float getScale() {
		return scale;
	}

	/**
     * Specifies the stretch factor of the texture.
     * @param stretch the stretch factor of the texture.
     * @min-value 1
     * @max-value 50+
     * @see #getStretch
     */
	public void setStretch(float stretch) {
		this.stretch = stretch;
	}

	/**
     * Returns the stretch factor of the texture.
     * @return the stretch factor of the texture.
     * @see #setStretch
     */
	public float getStretch() {
		return stretch;
	}

	/**
     * Specifies the angle of the texture.
     * @param angle the angle of the texture.
     * @angle
     * @see #getAngle
     */
	public void setAngle(float angle) {
		this.angle = angle;
		float cos = (float)Math.cos(angle);
		float sin = (float)Math.sin(angle);
		m00 = cos;
		m01 = sin;
		m10 = -sin;
		m11 = cos;
	}

	/**
     * Returns the angle of the texture.
     * @return the angle of the texture.
     * @see #setAngle
     */
	public float getAngle() {
		return angle;
	}

	/**
     * Specifies the turbulence of the texture.
     * @param turbulence the turbulence of the texture.
     * @min-value 0
     * @max-value 1
     * @see #getTurbulence
     */
	public void setTurbulence(float turbulence) {
		this.turbulence = turbulence;
	}

	/**
     * Returns the turbulence of the texture.
     * @return the turbulence of the texture.
     * @see #setTurbulence
     */
	public float getTurbulence() {
		return turbulence;
	}

    /**
     * Set the colormap to be used for the filter.
     * @param colormap the colormap
     * @see #getColormap
     */
	public void setColormap(Colormap colormap) {
		this.colormap = colormap;
	}
	
    /**
     * Get the colormap to be used for the filter.
     * @return the colormap
     * @see #setColormap
     */
	public Colormap getColormap() {
		return colormap;
	}
	
	/* (non-Javadoc)
	 * @see com.jhlabs.image.PointFilter#filterRGB(int, int, int)
	 */
	public int filterRGB(int x, int y, int rgb) {
		float nx = m00*x + m01*y;
		float ny = m10*x + m11*y;
		nx /= scale;
		ny /= scale * stretch;
		float f = turbulence == 1.0 ? Noise.noise2(nx, ny) : Noise.turbulence2(nx, ny, turbulence);
		f = (f * 0.5f) + 0.5f;
		f = ImageMath.gain(f, gain);
		f = ImageMath.bias(f, bias);
		f *= amount;
		int a = rgb & 0xff000000;
		int v;
		if (colormap != null)
			v = colormap.getColor(f);
		else {
			v = PixelUtils.clamp((int)(f*255));
			int r = v << 16;
			int g = v << 8;
			int b = v;
			v = a|r|g|b;
		}
		if (operation != PixelUtils.REPLACE)
			v = PixelUtils.combinePixels(rgb, v, operation);
		return v;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		return "Texture/Noise...";
	}
	
}
